home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 May: Tool Chest / Dev.CD May 97 TC.toast / Tool Chest / QuickDraw / Bitblitz 1.0 / Source / BlendUtils.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-10-09  |  14.4 KB  |  489 lines  |  [TEXT/MPS ]

  1. /*--------------------------------------------------------------------------------------
  2. //
  3. //    File:          BlendProcs.c
  4. //
  5. //    Contents:    Procedures that render blended fills.
  6. //
  7. //
  8. //    By Georgiann ("George") Delaney
  9. //    © 1989 - 1990, Apple Computer, Inc.
  10. //
  11. //--------------------------------------------------------------------------------------*/
  12.  
  13.  
  14.  
  15.  
  16. #pragma segment BlendSeg
  17.  
  18.  
  19. #include "MacHeaders.h"
  20.  
  21.  
  22.  
  23. /*--------------------------------------------------------------------------------------*/
  24. /*  Constants    */
  25.  
  26. #define    kGrayPatternRsrc    50
  27. #define    kNumGrayPatterns    50
  28.  
  29.  
  30.  
  31. /*--------------------------------------------------------------------------------------*/
  32. /*  Macro definitions  */
  33.  
  34. #define  RECT_BLEND_BAND_COUNT(span,bandWidth)            (((span-bandWidth)/2)/bandWidth)
  35. #define  RECT_BLEND_BAND_INC(span,bandCount,bandWidth)    (((span-bandWidth)/2)/bandCount)
  36. #define  RECT_BLEND_STEP(span,bandWidth)                (65535/(((span/2)-(bandWidth/2))/bandWidth))
  37.  
  38. #define  LINEAR_BLEND_BAND_COUNT(span,bandWidth)        (span/bandWidth)
  39. #define  LINEAR_BLEND_STEP(span,bandWidth)                (65535/(span/bandWidth))
  40.  
  41.  
  42. #define  MIN(x,y)        (((x) < (y)) ? (x) : (y))
  43. #define  MAX(x,y)        (((x) > (y)) ? (x) : (y))
  44.  
  45.  
  46.  
  47. /*--------------------------------------------------------------------------------------*/
  48. void  HLSRectBlend(Rect *boundRect, short saturation)
  49. /*    
  50. //    This procedure fills the specified rect with a concentric rectangular HLS blend 
  51. //    at the specified saturation.  The band size used for this fill is 1 pixel.  It is 
  52. //    assumed that the desired port as well as any desired clipping has already been set.
  53. */
  54. {
  55.     RGBColor    holdRGB,theRGB;
  56.     HSVColor    theHSV;
  57.     short        blendStep;
  58.     short        i;
  59.     short        span;
  60.     Rect        tempRect;
  61.      
  62.  
  63.     tempRect  = *boundRect;
  64.     
  65.                 /*  calculate the diameter of the specified rect  */
  66.     span      = MIN((tempRect.right-tempRect.left)/2, (tempRect.bottom - tempRect.top)/2);
  67.  
  68.                 /*  calculate the color increment for each band  */
  69.     blendStep = 65536 / span;    
  70.  
  71.                 /*  save off the current RGB  */
  72.     GetForeColor(&holdRGB);
  73.     
  74.                 /*  set the initial color  */
  75.     theHSV.value         = 65535;
  76.     theHSV.saturation     = saturation;
  77.     theHSV.hue             =  0;
  78.     
  79.                 /*  Generate the blend by converting the hls (hsv in mac terms) to 
  80.                     its RGB equivalent.  Set the forecolor to this RGB value.  Paint
  81.                     the rect.  Then increment the HLS value and band rect for the next
  82.                     iteration    
  83.                 */
  84.     for (i=0; i<span; i++)  {
  85.         HSV2RGB(&theHSV,&theRGB);
  86.         RGBForeColor(&theRGB);
  87.         PaintRect(&tempRect);
  88.         theHSV.hue += blendStep;
  89.         tempRect.top    +=1;
  90.         tempRect.left   +=1;
  91.         tempRect.right  -=1;
  92.         tempRect.bottom -=1;
  93.         }
  94.         
  95.                 /*  restore the original RGB  */
  96.     RGBForeColor(&holdRGB);
  97. }
  98.  
  99.  
  100. /*--------------------------------------------------------------------------------------*/
  101. void  HLSVLinearBlend(Rect *boundRect, short saturation)
  102. /*    
  103. //    This procedure fills the specified rect with a vertical HLS blend 
  104. //    at the specified saturation.  The band size used for this fill is 1 pixel.  It is 
  105. //    assumed that the desired port as well as any desired clipping has already been set.
  106. */
  107. {
  108.     RGBColor    holdRGB,theRGB;
  109.     HSVColor    theHSV;
  110.     short        blendStep;
  111.     short        height;
  112.     Rect        tempRect;
  113.     short        i;
  114.      
  115.  
  116.     tempRect = *boundRect;
  117.             
  118.                 /*  calculate the vertical distance the blend is to cover  */
  119.     height     = tempRect.bottom - tempRect.top;
  120.     
  121.                 /*  calculate the color increment for each band  */
  122.     blendStep = 65535 / height;    
  123.             
  124.                 /*  save off the current RGB  */
  125.     GetForeColor(&holdRGB);
  126.  
  127.                 /*  set the initial color  */
  128.     theHSV.value         = 65535;
  129.     theHSV.saturation     = saturation;
  130.     theHSV.hue             =  0;
  131.     
  132.                 /*  Initialize the rectangle that specifies the first band of the blend   */
  133.     tempRect.bottom = tempRect.top + 1;
  134.     
  135.                 /*  Generate the blend by converting the hls (hsv in mac terms) to 
  136.                     its RGB equivalent.  Set the forecolor to this RGB value.  Paint
  137.                     the rect.  Then increment the HLS value and offset the band rect for 
  138.                     the next iteration
  139.                 */
  140.     for (i=0; i<height; i++)  {
  141.         HSV2RGB(&theHSV,&theRGB);
  142.         RGBForeColor(&theRGB);
  143.         PaintRect(&tempRect);
  144.         theHSV.hue += blendStep;
  145.         tempRect.top    +=1;
  146.         tempRect.bottom +=1;
  147.         }
  148.  
  149.                 /*  restore the original RGB  */
  150.     RGBForeColor(&holdRGB);
  151. }
  152.  
  153.  
  154. /*--------------------------------------------------------------------------------------*/
  155. void  HLSHLinearBlend(Rect *boundRect, short saturation)
  156. /*    
  157. //    This procedure fills the specified rect with a horizontal HLS blend 
  158. //    at the specified saturation.  The band size used for this fill is 1 pixel.  It is 
  159. //    assumed that the desired port as well as any desired clipping has already been set.
  160. */
  161. {
  162.     RGBColor    holdRGB,theRGB;
  163.     HSVColor    theHSV;
  164.     short        blendStep;
  165.     short        width;
  166.     Rect        tempRect;
  167.     short        i;
  168.      
  169.  
  170.     tempRect = *boundRect;
  171.     
  172.                 /*  calculate the horizontal distance the blend is to cover  */
  173.     width     = tempRect.right-tempRect.left;
  174.     
  175.                 /*  calculate the color increment for each band  */
  176.     blendStep = 65535 / width;    
  177.             
  178.                 /*  save off the current RGB  */
  179.     GetForeColor(&holdRGB);
  180.  
  181.                 /*  set the initial color  */
  182.     theHSV.value         = 65535;
  183.     theHSV.saturation     = saturation;
  184.     theHSV.hue             =  0;
  185.     
  186.                 /*  Initialize the rectangle that specifies the first band of the blend   */
  187.     tempRect.right = tempRect.left + 1;
  188.     
  189.                 /*  Generate the blend by converting the hls (hsv in mac terms) to 
  190.                     its RGB equivalent.  Set the forecolor to this RGB value.  Paint
  191.                     the rect.  Then increment the HLS value and offset the band rect for 
  192.                     the next iteration
  193.                 */
  194.     for (i=0; i<width; i++)  {
  195.         HSV2RGB(&theHSV,&theRGB);
  196.         RGBForeColor(&theRGB);
  197.         PaintRect(&tempRect);
  198.         theHSV.hue        += blendStep;
  199.         tempRect.left  +=1;
  200.         tempRect.right +=1;
  201.         }
  202.  
  203.                 /*  restore the original RGB  */
  204.     RGBForeColor(&holdRGB);
  205. }
  206.  
  207.  
  208. /*--------------------------------------------------------------------------------------*/
  209. void  GrayRectBlend(Rect *boundRect)
  210. /*    
  211. //    This procedure fills the specified rect with a concentric rectangular gray scale blend 
  212. //    from black to white.  The band size used for this fill is 1 pixel.  It is 
  213. //    assumed that the desired port as well as any desired clipping has already been set.
  214. */
  215. {
  216.     RGBColor    holdRGB,theRGB;
  217.     short        blendStep;
  218.     short        i;
  219.     short        span;
  220.     Rect        tempRect;
  221.      
  222.  
  223.     tempRect     = *boundRect;
  224.     
  225.                 /*    calculate the diameter of the specified rect  */
  226.     span      = MIN((tempRect.right-tempRect.left)/2, (tempRect.bottom - tempRect.top)/2);
  227.  
  228.                 /*    calculate the color increment for each band  */
  229.     blendStep = 65536 / span;    
  230.  
  231.                 /*    save off the current RGB color  */
  232.     GetForeColor(&holdRGB);
  233.     
  234.                 /*    set the initial color  */
  235.     theRGB.red = theRGB.green = theRGB.blue = 0;
  236.     
  237.                 /*    Generate the blend by seting the forecolor to the RGB value.  Paint
  238.                     the rect.  Then increment the RGB value and band rect for the next
  239.                     iteration
  240.                 */
  241.     for (i=0; i<span; i++)  {
  242.         RGBForeColor(&theRGB);
  243.         PaintRect(&tempRect);
  244.         theRGB.red = theRGB.green = theRGB.blue = theRGB.red + blendStep;
  245.         tempRect.top    +=1;
  246.         tempRect.left   +=1;
  247.         tempRect.right  -=1;
  248.         tempRect.bottom -=1;
  249.         }
  250.         
  251.                 /*  restore the original RGB  */
  252.     RGBForeColor(&holdRGB);
  253. }
  254.  
  255.  
  256. /*--------------------------------------------------------------------------------------*/
  257. void  GrayVLinearBlend(Rect *boundRect)
  258. /*        
  259. //    This procedure fills the specified rect with a vertical gray scale blend 
  260. //    from black to white.  The band size used for this fill is 1 pixel.  It is 
  261. //    assumed that the desired port as well as any desired clipping has already been set.
  262. */
  263. {
  264.     RGBColor    holdRGB,theRGB;
  265.     short        blendStep;
  266.     short        i;
  267.     short        height;
  268.     Rect        tempRect;
  269.      
  270.  
  271.     tempRect  = *boundRect;
  272.  
  273.                 /*    calculate the vertical distance the blend is to cover  */
  274.     height    = tempRect.bottom - tempRect.top;
  275.  
  276.                 /*    calculate the color increment for each band  */
  277.     blendStep = 65535 / height;    
  278.  
  279.                 /*    save off the current RGB color  */
  280.     GetForeColor(&holdRGB);
  281.  
  282.                 /*    set the initial color  */
  283.     theRGB.red = theRGB.green = theRGB.blue = 0;
  284.     
  285.                 /*    Initialize the rectangle that specifies the first band of the blend   */
  286.     tempRect.bottom = tempRect.top + 1;
  287.     
  288.                 /*    Generate the blend by setting the forecolor to this RGB value.  Paint
  289.                     the rect.  Then increment the RGB value and offset the band rect for 
  290.                     the next iteration
  291.                 */
  292.     for (i=0; i<height; i++)  {
  293.         RGBForeColor(&theRGB);
  294.         PaintRect(&tempRect);
  295.         theRGB.red = theRGB.green = theRGB.blue = theRGB.red + blendStep;
  296.         tempRect.top    +=1;
  297.         tempRect.bottom +=1;
  298.         }
  299.  
  300.                 /*  restore the original RGB  */
  301.     RGBForeColor(&holdRGB);
  302. }
  303.  
  304.  
  305. /*--------------------------------------------------------------------------------------*/
  306. void  GrayHLinearBlend(Rect *boundRect)
  307. /*    
  308. //    This procedure fills the specified rect with a horizontal gray scale blend 
  309. //    from black to white.  The band size used for this fill is 1 pixel.  It is 
  310. //    assumed that the desired port as well as any desired clipping has already been set.
  311. */
  312. {
  313.     RGBColor    holdRGB,theRGB;
  314.     short        blendStep;
  315.     short        i;
  316.     short        width;
  317.     Rect        tempRect;
  318.      
  319.  
  320.     tempRect  = *boundRect;
  321.  
  322.                 /*  calculate the horizontal distance the blend is to cover  */
  323.     width     = tempRect.right-tempRect.left;
  324.  
  325.                 /*  calculate the color increment for each band  */
  326.     blendStep = 65535 / width;    
  327.  
  328.                 /*    save off the current RGB color  */
  329.     GetForeColor(&holdRGB);
  330.  
  331.                 /*  set the initial color  */
  332.     theRGB.red = theRGB.green = theRGB.blue = 0;
  333.     
  334.                 /*  Initialize the rectangle that specifies the first band of the blend   */
  335.     tempRect.right = tempRect.left + 1;
  336.     
  337.                 /*  Generate the blend by setting the forecolor to this RGB value.  Paint
  338.                     the rect.  Then increment the RGB value and offset the band rect for 
  339.                     the next iteration
  340.                 */
  341.     for (i=0; i<width; i++)  {
  342.         RGBForeColor(&theRGB);
  343.         PaintRect(&tempRect);
  344.         theRGB.red = theRGB.green = theRGB.blue = theRGB.red + blendStep;
  345.         tempRect.left  +=1;
  346.         tempRect.right +=1;
  347.         }
  348.  
  349.                 /*  restore the original RGB  */
  350.     RGBForeColor(&holdRGB);
  351. }
  352.  
  353. /*--------------------------------------------------------------------------------------*/
  354. void  GrayPatRectBlend(Rect *boundRect)
  355. /*    
  356. //    This procedure fills the specified rect with a concentric rectangular gray scale pattern blend
  357. //    from black to white.  The band size used for this fill is calculated by dividing the shorter 
  358. //    the horizontal and vertical diameters of the specified rect by the number of gray patterns in 
  359. //  the gray pattern resource.  It is assumed that the desired port as well as any desired clipping
  360. //  has already been set.
  361. */
  362.  
  363. {
  364.     register    i;
  365.     double        bandWidth;
  366.     double        distance;
  367.     Rect        origRect,tempRect;
  368.     Pattern        thePat;
  369.           
  370.  
  371.     origRect = tempRect    = *boundRect;
  372.     
  373.                 /*    calculate the width of each band  */
  374.     bandWidth = (double)(MIN((tempRect.right-tempRect.left)/2, (tempRect.bottom-tempRect.top)/2)) / (double)(kNumGrayPatterns+1);    
  375.     distance  = bandWidth;
  376.     
  377.                 /*  There is a pattern resource consisting of 64 shades of gray in MacLib.rsrc 
  378.                 //  that gives a pretty good approximation of a gray ramp from white to black.
  379.                 //  The following loop performs the actual imaging of the ramp's 64 gray bands.
  380.                 */
  381.     for (i=kNumGrayPatterns; i>=1; i--)  {
  382.         GetIndPattern(&thePat, kGrayPatternRsrc, i);  
  383.         FillRect(&tempRect,thePat);
  384.         
  385.         distance  += bandWidth;
  386.         tempRect.top    = origRect.top    + distance;
  387.         tempRect.left   = origRect.left   + distance;
  388.         tempRect.right  = origRect.right  - distance;
  389.         tempRect.bottom = origRect.bottom - distance;
  390.         }
  391. }
  392.  
  393.  
  394. /*--------------------------------------------------------------------------------------*/
  395. void  GrayPatVLinearBlend(Rect *boundRect)
  396. /*    
  397. //    This procedure fills the specified rect with a vertical gray scale pattern blend
  398. //    from black to white.  The band size used for this fill is calculated by dividing the width
  399. //  of the specified blend by the number of gray patterns in the gray pattern resource.  It is 
  400. //    assumed that the desired port as well as any desired clipping has already been set.
  401. */
  402. {
  403.     register    i;
  404.     double        theTop;
  405.     double        bandHeight;
  406.     double        distance;
  407.     Rect        tempRect;
  408.     Pattern        thePat;
  409.      
  410.  
  411.     tempRect  = *boundRect;
  412.     
  413.                 /*  silly, but saves a pointer dereference in the blend loop  */
  414.     theTop      = (double)tempRect.top;        
  415.  
  416.                 /*  calculate the width of each band  */
  417.     bandHeight = ((double)(tempRect.bottom-tempRect.top)) / (double)kNumGrayPatterns;    
  418.  
  419.                 /*  Initialize the rectangle that specifies the first band of the blend   */
  420.     tempRect.bottom = tempRect.top + bandHeight;
  421.     distance        = bandHeight;
  422.     
  423.                 /*  There is a pattern resource consisting of 64 shades of gray in MacLib.rsrc 
  424.                 //  that gives a pretty good approximation of a gray ramp from white to black.
  425.                 //  The following loop performs the actual imaging of the ramp's 64 gray bands.
  426.                 */
  427.     for (i=kNumGrayPatterns; i>1; i--)  {
  428.         GetIndPattern(&thePat, kGrayPatternRsrc, i);  
  429.         FillRect(&tempRect,thePat);
  430.  
  431.         distance         += bandHeight;
  432.         tempRect.top     = tempRect.bottom;
  433.         tempRect.bottom  = (short)(theTop + distance);
  434.         }
  435.  
  436.     tempRect.bottom  = boundRect->bottom;
  437.     GetIndPattern(&thePat,kGrayPatternRsrc,1);
  438.     FillRect(&tempRect,thePat);
  439. }
  440.  
  441.  
  442. /*--------------------------------------------------------------------------------------*/
  443. void  GrayPatHLinearBlend(Rect *boundRect)
  444. /*    
  445. //    This procedure fills the specified rect with a horizontal gray scale pattern blend
  446. //    from black to white.  The band size used for this fill is calculated by dividing the width
  447. //  of the specified blend by the number of gray patterns in the gray pattern resource.  It is 
  448. //    assumed that the desired port as well as any desired clipping has already been set.
  449. */
  450. {
  451.     register    i;
  452.     double        farLeft;
  453.     double        bandWidth;
  454.     double        distance;
  455.     Rect        tempRect;
  456.     Pattern        thePat;
  457.      
  458.  
  459.     tempRect  = *boundRect;
  460.     
  461.                 /*  silly, but saves a pointer dereference in the blend loop  */
  462.     farLeft      = (double)tempRect.left;        
  463.  
  464.                 /*  calculate the width of each band  */
  465.     bandWidth = ((double)(tempRect.right-tempRect.left)) / (double)kNumGrayPatterns;    
  466.  
  467.                 /*  Initialize the rectangle that specifies the first band of the blend   */
  468.     tempRect.right = tempRect.left + bandWidth;
  469.     distance       = bandWidth;
  470.     
  471.                 /*  There is a pattern resource consisting of 64 shades of gray in MacLib.rsrc 
  472.                 //  that gives a pretty good approximation of a gray ramp from white to black.
  473.                 //  The following loop performs the actual imaging of the ramp's 64 gray bands.
  474.                 */
  475.     for (i=kNumGrayPatterns; i>1; i--)  {
  476.         GetIndPattern(&thePat, kGrayPatternRsrc, i);  
  477.         FillRect(&tempRect,thePat);
  478.  
  479.         distance        += bandWidth;
  480.         tempRect.left   = tempRect.right;
  481.         tempRect.right  = (short)(farLeft + distance);
  482.         }
  483.  
  484.     tempRect.right  = boundRect->right;
  485.     GetIndPattern(&thePat,kGrayPatternRsrc,1);
  486.     FillRect(&tempRect,thePat);
  487. }
  488.  
  489.